-- Copyright (c) 2015,2016 Lucky Byte, Inc.
--
-- Summary : 发卡行识别码 Bank Identification Code
--
-- Author  : xiaohu <xiaohu@lucky-byte.com>
-- Since   : 2015.12.6
--
-- History
--  * 2015.12.06 : 创建此文件
--  * 2016.07.27 : 增加借贷记判定 is_debit
--

local _card_types = {
    [1] = '非标卡表',
    [2] = '农民工卡表',
    [3] = '转账卡表',
    [4] = '业务卡表',
}

local _debit_credit_flags = {
    [1] = '借记卡',
    [2] = '贷记卡',
    [3] = '准贷记卡',
    [4] = '预付卡'
}


local function _log_bininfo(bininfo)
    logger.debug('卡表[%s]，卡名[%s]，卡BIN[%s]，卡种[%s]，发卡机构[%s][%s].',
        _card_types[bininfo.get('card_type')] or '未知',
        bininfo.get('card_name') or '未知',
        bininfo.get('bin_num') or '未知',
        _debit_credit_flags[bininfo.get('debit_credit_flag')] or '未知',
        bininfo.get('issuer_code') or '未知',
        bininfo.get('issuer_name') or '未知')
end


-- 通过卡号查询卡 bin 数据库记录
--
-- 参数:
--    card_no : 卡号，数字或字符串
--
-- 返回:
--    成功返回 数据库记录，失败返回 nil
--
-- 说明:
--    这个函数尝试从最大位数的 bin 开始匹配，直到最小位数的卡 bin 为止，
--    以最先匹配到的结果为准，其中最大位数和最小位数通过数据库查询获取。
--    如果一个卡号即能匹配一条 6 位卡 bin 记录，同时又能匹配一条 4 位卡 bin 记录，
--    那么将返回 6 位卡 bin 的记录.
--
-- 示例:
--    local bininfo = _query(6225763322334)
--    if bininfo then
--        print('发卡行代码: ' .. bininfo.get('issuer_code'))
--    else
--        print('未查询到卡 bin 信息')
--    end
--
local function _query(card_no)
    if not card_no then
        logger.error('卡号为空，不能查询其卡 BIN.')
        return nil
    end
    local card_no_len = string.len(card_no)

    -- 从数据库中实时获取最长和最短的卡 bin 长度
    local t = jdbc.select(
        'select max(bin_len) as max, min(bin_len) as min from pay_cardbin')
    local r = t.get_record(0)
    local max, min = r.get('max'), r.get('min')

    -- 从最大长度开始匹配，逐个递减，直到找到匹配的记录为止(或者没有匹配记录)
    for bin_len = max, min, -1 do
        local bin_num = string.sub(card_no, 1, bin_len)
        local result = jdbc.select([[
            select * from pay_cardbin where
              bin_num = ? and bin_len = ? and card_no_len = ?
              order by card_type limit 1
        ]], bin_num, bin_len, card_no_len)
        if result and result.count > 0 then
            local _bininfo = result.get_record(0)
            logger.debug('查询到卡号[%s]的卡BIN信息如下:', card_no)
            _log_bininfo(_bininfo)
            return _bininfo
        end
    end
    return nil
end


-- 通过卡号判断借贷记
--
-- 如果卡号为空或者不能获取卡 BIN 信息，则默认返回 false，作为贷记处理
--
local _is_debit = function(card_no)
    if string.trimlen(card_no) == 0 then
        return false
    end
    -- 如果不能查询到卡BIN 信息，则作为贷记卡处理
    local _bininfo = _query(card_no)
    if not _bininfo then
        logger.warn('通过卡号[%s]未查询到卡BIN信息，默认作为贷记卡处理.', card_no)
        return false
    end
    if _bininfo.get('debit_credit_flag') == 1 then
        logger.debug('通过卡号[%s]判定此卡为借记卡.', card_no)
        return true
    end
    -- 准贷记卡与预付卡作为贷记卡处理
    logger.debug('通过卡号[%s]判定此卡为贷记卡.', card_no)
    return false
end


-- 外部接口
core = core or {}
core.cardbin = {
    query    = _query,
    is_debit = _is_debit,
}
